#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试日志系统

本测试文件专门测试日志系统的配置和功能，
包括日志级别、输出格式、文件写入等。
"""

import asyncio
import pytest
import sys
import os
import tempfile
import time
from pathlib import Path
from loguru import logger

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

from src.utils.logger import setup_logger
from src.config import load_config


class Test日志系统:
    """测试日志系统的测试类"""
    
    @pytest.fixture
    def temp_log_dir(self):
        """创建临时日志目录"""
        with tempfile.TemporaryDirectory() as temp_dir:
            yield Path(temp_dir)
    
    def test_日志配置加载(self):
        """测试日志配置的加载"""
        try:
            # 加载配置
            config = load_config()
            
            # 检查日志配置是否存在
            assert 'logging' in config, "配置中缺少logging部分"
            
            logging_config = config['logging']
            
            # 检查基本配置项
            expected_keys = ['level', 'format', 'file_enabled', 'console_enabled']
            for key in expected_keys:
                assert key in logging_config, f"日志配置缺少{key}字段"
            
            # 检查日志级别是否有效
            valid_levels = ['TRACE', 'DEBUG', 'INFO', 'SUCCESS', 'WARNING', 'ERROR', 'CRITICAL']
            assert logging_config['level'] in valid_levels, f"无效的日志级别: {logging_config['level']}"
            
            logger.info("日志配置加载测试通过")
            
        except Exception as e:
            logger.error(f"日志配置加载失败: {e}")
            raise
    
    def test_日志器初始化(self, temp_log_dir):
        """测试日志器的初始化"""
        try:
            # 创建测试配置
            test_config = {
                'level': 'DEBUG',
                'format': '{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} - {message}',
                'file_enabled': True,
                'console_enabled': True,
                'file_path': str(temp_log_dir / 'test.log'),
                'rotation': '10 MB',
                'retention': '7 days'
            }
            
            # 初始化日志器
            setup_logger(test_config)
            
            # 测试不同级别的日志
            logger.debug("这是一条调试信息")
            logger.info("这是一条信息")
            logger.warning("这是一条警告")
            logger.error("这是一条错误")
            
            # 检查日志文件是否创建
            log_file = Path(test_config['file_path'])
            assert log_file.exists(), "日志文件未创建"
            
            # 检查日志文件内容
            log_content = log_file.read_text(encoding='utf-8')
            assert "这是一条调试信息" in log_content, "调试信息未写入日志文件"
            assert "这是一条信息" in log_content, "信息未写入日志文件"
            assert "这是一条警告" in log_content, "警告未写入日志文件"
            assert "这是一条错误" in log_content, "错误未写入日志文件"
            
            logger.info("日志器初始化测试通过")
            
        except Exception as e:
            logger.error(f"日志器初始化失败: {e}")
            raise
    
    def test_日志级别过滤(self, temp_log_dir):
        """测试日志级别过滤功能"""
        try:
            # 创建INFO级别的日志配置
            test_config = {
                'level': 'INFO',
                'format': '{time} | {level} | {message}',
                'file_enabled': True,
                'console_enabled': False,
                'file_path': str(temp_log_dir / 'level_test.log')
            }
            
            # 重新配置日志器
            logger.remove()
            setup_logger(test_config)
            
            # 记录不同级别的日志
            logger.debug("调试信息 - 不应出现")
            logger.info("信息 - 应该出现")
            logger.warning("警告 - 应该出现")
            logger.error("错误 - 应该出现")
            
            # 等待日志写入
            time.sleep(0.1)
            
            # 检查日志文件内容
            log_file = Path(test_config['file_path'])
            log_content = log_file.read_text(encoding='utf-8')
            
            # DEBUG级别的日志不应出现
            assert "调试信息 - 不应出现" not in log_content, "DEBUG级别日志不应被记录"
            
            # INFO及以上级别的日志应该出现
            assert "信息 - 应该出现" in log_content, "INFO级别日志应被记录"
            assert "警告 - 应该出现" in log_content, "WARNING级别日志应被记录"
            assert "错误 - 应该出现" in log_content, "ERROR级别日志应被记录"
            
            logger.info("日志级别过滤测试通过")
            
        except Exception as e:
            logger.error(f"日志级别过滤测试失败: {e}")
            raise
    
    def test_日志格式化(self, temp_log_dir):
        """测试日志格式化功能"""
        try:
            # 创建自定义格式的日志配置
            custom_format = "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} | {message}"
            test_config = {
                'level': 'DEBUG',
                'format': custom_format,
                'file_enabled': True,
                'console_enabled': False,
                'file_path': str(temp_log_dir / 'format_test.log')
            }
            
            # 重新配置日志器
            logger.remove()
            setup_logger(test_config)
            
            # 记录测试日志
            test_message = "格式化测试消息"
            logger.info(test_message)
            
            # 等待日志写入
            time.sleep(0.1)
            
            # 检查日志文件内容
            log_file = Path(test_config['file_path'])
            log_content = log_file.read_text(encoding='utf-8')
            
            # 检查格式是否正确
            lines = log_content.strip().split('\n')
            assert len(lines) > 0, "日志文件应包含至少一行"
            
            log_line = lines[-1]  # 获取最后一行
            
            # 检查格式组件
            assert test_message in log_line, "日志消息应在日志行中"
            assert "INFO" in log_line, "日志级别应在日志行中"
            assert ":" in log_line, "日志行应包含分隔符"
            
            # 检查时间戳格式（YYYY-MM-DD HH:mm:ss.SSS）
            import re
            timestamp_pattern = r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}'
            assert re.search(timestamp_pattern, log_line), "时间戳格式不正确"
            
            logger.info("日志格式化测试通过")
            
        except Exception as e:
            logger.error(f"日志格式化测试失败: {e}")
            raise
    
    def test_日志轮转(self, temp_log_dir):
        """测试日志轮转功能"""
        try:
            # 创建小文件大小的日志配置以触发轮转
            test_config = {
                'level': 'DEBUG',
                'format': '{time} | {level} | {message}',
                'file_enabled': True,
                'console_enabled': False,
                'file_path': str(temp_log_dir / 'rotation_test.log'),
                'rotation': '1 KB',  # 很小的文件大小
                'retention': '3 files'
            }
            
            # 重新配置日志器
            logger.remove()
            setup_logger(test_config)
            
            # 写入大量日志以触发轮转
            for i in range(100):
                logger.info(f"这是第{i+1}条测试日志，用于触发日志轮转功能。" * 10)
            
            # 等待日志写入和轮转
            time.sleep(0.5)
            
            # 检查是否生成了轮转文件
            log_files = list(temp_log_dir.glob('rotation_test*.log'))
            assert len(log_files) > 1, "应该生成多个日志文件（轮转）"
            
            # 检查主日志文件存在
            main_log = temp_log_dir / 'rotation_test.log'
            assert main_log.exists(), "主日志文件应该存在"
            
            logger.info(f"日志轮转测试通过，生成了{len(log_files)}个日志文件")
            
        except Exception as e:
            logger.error(f"日志轮转测试失败: {e}")
            raise
    
    def test_异常日志记录(self, temp_log_dir):
        """测试异常日志记录功能"""
        try:
            # 创建日志配置
            test_config = {
                'level': 'DEBUG',
                'format': '{time} | {level} | {name}:{function}:{line} | {message}',
                'file_enabled': True,
                'console_enabled': False,
                'file_path': str(temp_log_dir / 'exception_test.log')
            }
            
            # 重新配置日志器
            logger.remove()
            setup_logger(test_config)
            
            # 模拟异常并记录
            try:
                # 故意触发异常
                result = 1 / 0
            except ZeroDivisionError as e:
                logger.exception("捕获到除零异常")
                logger.error(f"异常详情: {str(e)}")
            
            # 等待日志写入
            time.sleep(0.1)
            
            # 检查日志文件内容
            log_file = Path(test_config['file_path'])
            log_content = log_file.read_text(encoding='utf-8')
            
            # 检查异常信息是否被记录
            assert "捕获到除零异常" in log_content, "异常消息应被记录"
            assert "ZeroDivisionError" in log_content, "异常类型应被记录"
            assert "Traceback" in log_content, "异常堆栈应被记录"
            assert "division by zero" in log_content, "异常详情应被记录"
            
            logger.info("异常日志记录测试通过")
            
        except Exception as e:
            logger.error(f"异常日志记录测试失败: {e}")
            raise
    
    def test_并发日志记录(self, temp_log_dir):
        """测试并发日志记录功能"""
        try:
            # 创建日志配置
            test_config = {
                'level': 'DEBUG',
                'format': '{time} | {level} | {process} | {thread} | {message}',
                'file_enabled': True,
                'console_enabled': False,
                'file_path': str(temp_log_dir / 'concurrent_test.log')
            }
            
            # 重新配置日志器
            logger.remove()
            setup_logger(test_config)
            
            import threading
            import concurrent.futures
            
            def log_worker(worker_id, num_logs):
                """工作线程函数"""
                for i in range(num_logs):
                    logger.info(f"工作线程{worker_id} - 日志{i+1}")
                    time.sleep(0.001)  # 短暂延迟
            
            # 启动多个线程并发写日志
            num_workers = 5
            logs_per_worker = 20
            
            with concurrent.futures.ThreadPoolExecutor(max_workers=num_workers) as executor:
                futures = []
                for worker_id in range(num_workers):
                    future = executor.submit(log_worker, worker_id, logs_per_worker)
                    futures.append(future)
                
                # 等待所有线程完成
                concurrent.futures.wait(futures)
            
            # 等待日志写入
            time.sleep(0.5)
            
            # 检查日志文件内容
            log_file = Path(test_config['file_path'])
            log_content = log_file.read_text(encoding='utf-8')
            
            # 统计日志行数
            log_lines = log_content.strip().split('\n')
            expected_lines = num_workers * logs_per_worker
            
            assert len(log_lines) >= expected_lines, f"日志行数不足，期望{expected_lines}，实际{len(log_lines)}"
            
            # 检查每个工作线程的日志都存在
            for worker_id in range(num_workers):
                worker_logs = [line for line in log_lines if f"工作线程{worker_id}" in line]
                assert len(worker_logs) == logs_per_worker, f"工作线程{worker_id}的日志数量不正确"
            
            logger.info(f"并发日志记录测试通过，记录了{len(log_lines)}行日志")
            
        except Exception as e:
            logger.error(f"并发日志记录测试失败: {e}")
            raise
    
    def test_日志性能(self, temp_log_dir):
        """测试日志记录性能"""
        try:
            # 创建日志配置
            test_config = {
                'level': 'INFO',
                'format': '{time} | {level} | {message}',
                'file_enabled': True,
                'console_enabled': False,
                'file_path': str(temp_log_dir / 'performance_test.log')
            }
            
            # 重新配置日志器
            logger.remove()
            setup_logger(test_config)
            
            # 性能测试
            num_logs = 1000
            start_time = time.time()
            
            for i in range(num_logs):
                logger.info(f"性能测试日志 {i+1}")
            
            end_time = time.time()
            duration = end_time - start_time
            
            # 等待日志写入
            time.sleep(0.5)
            
            # 检查日志文件
            log_file = Path(test_config['file_path'])
            log_content = log_file.read_text(encoding='utf-8')
            log_lines = log_content.strip().split('\n')
            
            assert len(log_lines) >= num_logs, "日志数量不足"
            
            # 性能指标
            logs_per_second = num_logs / duration
            
            logger.info(f"性能测试完成: {num_logs}条日志，耗时{duration:.2f}秒，速度{logs_per_second:.0f}条/秒")
            
            # 性能断言（根据实际情况调整）
            assert logs_per_second > 100, "日志记录速度过慢"
            assert duration < 10, "日志记录时间过长"
            
        except Exception as e:
            logger.error(f"日志性能测试失败: {e}")
            raise


if __name__ == "__main__":
    # 配置日志
    logger.remove()
    logger.add(
        sys.stdout,
        format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
        level="INFO"
    )
    
    # 运行测试
    pytest.main([__file__, "-v", "-s"])